<?php

namespace App\Service\PayApi;

use App\Constants\ErrorForPayApi;
use App\Constants\XZXResponseCode;
use App\Model\Dao\RiskTradeOrderDao;
use App\Model\Dao\TradeOrderDetailDao;
use App\Model\Enum\OrderTransStatusEnum;
use App\Service\CommonRiskService;
use App\Utils\CustomUtils;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\Arr;

/**
 * Class RiskAndDispatchService
 * 风控调度
 *
 * @package App\Service\PayApi
 */
class RiskAndDispatchService {

    /**
     * @var TradeOrderService
     * @Inject()
     */
    protected $TradeOrderService;

    /**
     * @var TradeOrderDetailDao
     * @Inject()
     */
    protected $TradeOrderDetailDao;

    /**
     * @var RiskTradeOrderDao
     * @Inject()
     */
    protected $RiskTradeOrderDao;

    /**
     * @var CommonRiskService
     * @Inject()
     */
    protected $CommonRiskService;

    /**
     * 风控调度
     *
     * @param $mch
     * @param $detail
     * @param $base
     * @param $receive
     * @param $platformToBank
     *
     * @return mixed
     * @throws \Exception|\Throwable
     */
    public function riskAndDispatch ($mch, $detail, $base, $receive, $platformToBank) {


        // 风控/调度检查, 带上需要校验的参数

        // 风控/调度检查参数构造
        $reqRisk = [

            // 基础信息
            'mchNo'            => $detail['mchNo'],
            'mchTransAmount'   => $detail['mchTransAmount'],
            'mchTransCurrency' => $detail['mchTransCurrency'],
            'mchTransTime'     => $detail['mchTransTime'],

            // 支付类型
            'payType'          => $detail['channelType'], // 支付类型

            // 调度列表
            'bankTransList'    => $platformToBank, // 调度列表

            // 风控检查参数
            'riskParam'        => [
                'mchNo'            => $detail['mchNo'],
                'tradeNo'          => $detail['tradeNo'],
                'mchTransAmount'   => $detail['mchTransAmount'],
                'mchTransCurrency' => $detail['mchTransCurrency'],
                'mchTransTime'     => $detail['mchTransTime'],
                'ipAddress'        => $detail['ipAddress'],
                'mchUrl'           => $detail['mchUrl'],
                'webInfo'          => $detail['webInfo'],

                'cardType'      => $receive['cardType'],
                'cardNo'        => $receive['cardNo'],
                'cardCountry'   => $receive['cardCountry'],
                'cardState'     => $receive['cardState'],
                'cardCity'      => $receive['cardCity'],
                'cardAddress'   => $receive['cardAddress'],
                'cardFullPhone' => $receive['cardFullPhone'],
                'cardEmail'     => $receive['cardEmail'],
                'cardZipCode'   => $receive['cardZipCode'],
                'cardFullName'  => $receive['cardFullName'],

                'grCountry'     => $receive['grCountry'],
                'grState'       => $receive['grState'],
                'grCity'        => $receive['grCity'],
                'grRegion'      => $receive['grCountry'],
                'grAddress'     => $receive['grAddress'],
                'grZipCode'     => $receive['grZipCode'],
                'grEmail'       => $receive['grEmail'],
                'grPhoneNumber' => $receive['grPhoneNumber'],
                'grPerName'     => $receive['grPerName'],
                'goodsInfo'     => $receive['goodsInfo'],
            ],

        ];

        try {
            // 请求风控模块接口
            $reRisk = $this->CommonRiskService->riskAndDispatch($reqRisk);
        } catch (\Throwable $e) {

            // 请求风控模块失败
            $code    = 1;
            $message = $e->getMessage();

            $this->TradeOrderService->setOrderBaseFail($detail['tradeNo'], $code, $message);

            $this->TradeOrderDetailDao->set($detail['id'], ['transStatus' => OrderTransStatusEnum::SERVICE_ERROR]);

            throw new \Exception(sprintf('[%s] ', trans('pay.risk.log_label')).$message, $code);
        }

        CustomUtils::xzxDebug('风控调度结果', $reRisk);

        // // debug 测试返回
        // $reRisk = CustomUtils::buildSuccess([
        //     'mchNo'      => 'test-mch-catt',
        //     'channel'    => [
        //         "collectionId"    => "test-collection-catt",
        //         "channelId"       => "channel-3",
        //         "channelNo"       => "channel-3",
        //         "channelName"     => "channel-3",
        //         "channelTransCurrency"    => "CNY",
        //         "channelTransAmount" => 1,
        //         "channelLimitCurrency"    => "CNY",
        //         "channelLimitAmount" => 1,
        //         "year"            => "2021",
        //         "month"           => "02",
        //         "day"             => "05",
        //     ],
        //     'risk'       => [],
        //     'whiteText'  => [],
        //     'suspicious' => [],
        // ]);

        $riskData = $reRisk['data'];

        // 处理风控返回信息(记录风控信息)
        $this->_handleRiskResult($detail, $riskData);

        if (CustomUtils::isError($reRisk)) {

            $code    = 1;
            $message = $reRisk['message'];

            // 更新订单跟踪状态
            $this->TradeOrderService->setOrderBaseFail($detail['tradeNo'], $code, $message);

            // 更新订单状态为风控驳回
            $this->TradeOrderDetailDao->set($detail['id'], ['transStatus' => OrderTransStatusEnum::RISK_CONTROL_BLOCK]);

            throw new \Exception($message, $code);
        }

        // 记录限额扣除汇率
        $this->TradeOrderDetailDao->update($detail['id'], [
            'channelLimitCurrency' => $riskData['channel']['channelLimitCurrency'],
            'channelLimitAmount'   => $riskData['channel']['channelLimitAmount'],
        ]);

        return $riskData;
    }

    /**
     * 处理风控返回信息
     *
     * @param $orderDetail
     * @param $riskData
     *
     * @throws \Throwable
     */
    protected function _handleRiskResult ($orderDetail, $riskData) {

        Db::beginTransaction();

        try {

            // 全局/商户风控
            if (isset($riskData['risk']['ruleId']) && !empty($riskData['risk']['ruleId'])) {

                $info = [
                    'id'           => CustomUtils::createUUID(),
                    'orderId'      => $orderDetail['id'],
                    'tradeNo'      => $orderDetail['tradeNo'],
                    'mchId'        => $orderDetail['mchId'],
                    'mchNo'        => $orderDetail['mchNo'],
                    'type'         => 1,
                    'payWebSite'   => '',
                    'collectionId' => Arr::get($riskData, 'risk.collectionId', ''),
                    'ruleId'       => $riskData['risk']['ruleId'],
                    'info'         => $riskData['risk']['message'],
                    'action'       => 1,
                ];

                $this->RiskTradeOrderDao->insert($info);
            }

            // 可疑风控
            if (isset($riskData['suspicious']['ruleId']) && !empty($riskData['suspicious']['ruleId'])) {

                $info = [
                    'id'           => CustomUtils::createUUID(),
                    'orderId'      => $orderDetail['id'],
                    'tradeNo'      => $orderDetail['tradeNo'],
                    'mchId'        => $orderDetail['mchId'],
                    'mchNo'        => $orderDetail['mchNo'],
                    'type'         => 2,
                    'payWebSite'   => '',
                    'collectionId' => Arr::get($riskData, 'suspicious.collectionId', ''),
                    'ruleId'       => $riskData['suspicious']['ruleId'],
                    'info'         => $riskData['suspicious']['message'],
                    'action'       => 2,
                ];

                $this->RiskTradeOrderDao->insert($info);
            }

            // 白名单
            if (isset($riskData['whiteText']['ruleId']) && !empty($riskData['whiteText']['ruleId'])) {

                $info = [
                    'id'           => CustomUtils::createUUID(),
                    'orderId'      => $orderDetail['id'],
                    'tradeNo'      => $orderDetail['tradeNo'],
                    'mchId'        => $orderDetail['mchId'],
                    'mchNo'        => $orderDetail['mchNo'],
                    'type'         => 3,
                    'collectionId' => Arr::get($riskData, 'whiteText.collectionId', ''),
                    'ruleId'       => $riskData['whiteText']['ruleId'],
                    'info'         => $riskData['whiteText']['message'],
                    'action'       => 1,
                ];

                $this->RiskTradeOrderDao->insert($info);
            }

        } catch (\Throwable $e) {
            Db::rollBack();
            // 更新订单跟踪状态
            $this->TradeOrderService->setOrderBaseFail($orderDetail['tradeNo'], XZXResponseCode::FAILED_CODE, $e->getMessage());
            throw $e;
        }

        Db::commit();
    }

}
